package com.intelligentclass.controller;

import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.intelligentclass.constant.UserType;
import com.intelligentclass.entity.Student;
import com.intelligentclass.entity.Teacher;
import com.intelligentclass.exception.UserTypeException;
import com.intelligentclass.mydata.MyJson;
import com.intelligentclass.requestItem.LoginItem;
import com.intelligentclass.requestItem.ModifyPasswordItem;
import com.intelligentclass.services.StudentService;
import com.intelligentclass.services.TeacherService;
import com.intelligentclass.utils.JWTUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

@RestController
@CrossOrigin(origins = "*")
public class LoginController {

    private final StudentService studentService;
    private final TeacherService teacherService;

    @Autowired
    public LoginController(StudentService studentService, TeacherService teacherService) {
        this.studentService = studentService;
        this.teacherService = teacherService;
    }

    /**
     * @param login
     *      login contains username & password
     * @return
     *      if login is successful,
     *      it will return a responseEntity which contains login status(1 for student, 2 for teacher),
     *      loginToken with JWT encryption to identify user in later functions,
     *      real name of user
     *      and a message "Login Successfully"
     *
     *      else,
     *
     */
    @PostMapping("/api/login")
    public ResponseEntity<?> login(@RequestBody LoginItem login) {
        MyJson json = new MyJson();

        String username = login.getUsername();
        String password = login.getPassword();

        Student s = studentService.searchBySno(username);
        Teacher t = teacherService.searchByTno(username);

        if(s != null){
            System.out.println("student");
        }
        if(t != null){
            System.out.println("teacher");
        }

        //check if it is invalid id
        if (s == null && t == null) {
            json.setStatus(400);
            json.setMessage("Wrong student number");
            json.addData("status", 0);
            return ResponseEntity.ok().body(json.toString());
        }

        //check if it is teacher and if the password is correct
        if(t == null && password.equals(s.getPassword())) {
            json.setStatus(200);

            String token = "";
            token = JWTUtil.generateToken(UserType.STUDENT, username);

            json.addData("status", UserType.STUDENT);
            json.addData("token", token);
            json.addData("name", s.getSname());
            json.setMessage("Login successfully");

            return ResponseEntity.ok().body(json.toString());
        }
        //check if it is student and if the password is correct
        else if(s == null && password.equals(t.getPassword())) {
            json.setStatus(200);

            String token = "";
            token = JWTUtil.generateToken(UserType.TEACHER, username);

            json.addData("status", UserType.TEACHER);
            json.addData("token", token);
            json.addData("name", t.getTname());
            json.setMessage("Login successfully");

            return ResponseEntity.ok().body(json.toString());
        }
        else{
            json.setStatus(400);
            json.addData("status", 0);
            json.setMessage("Wrong password");
            return ResponseEntity.ok().body(json.toString());
        }
    }

    /**
     *
     * @param headers
     *      must contain a valid token used to identify if the user is correct
     * @param modify
     *      this is used to map the modified password
     * @return
     */
    @PostMapping("/api/modifyPassword")
    private ResponseEntity<?> modifyPassword(@RequestHeader Map<String, String> headers, @RequestBody ModifyPasswordItem modify) {
        String token = headers.get("token");
        MyJson json = new MyJson();
        DecodedJWT jwt;
        try{
            jwt = JWTUtil.verifyToken(token);
            int userType = jwt.getClaim("usertype").asInt();
            if(userType != UserType.STUDENT && userType != UserType.TEACHER) {
                throw new UserTypeException();
            }

            else if(userType == UserType.STUDENT){
                String username = jwt.getClaim("username").asString();
                Student stu = studentService.searchBySno(username);

                stu.setPassword(modify.getPassword());
                studentService.save(stu);

                json.setMessage("Successfully modified password");
                json.setStatus(200);
                json.addData("status", 0);
                json.addData("token", JWTUtil.updateToken(token));
                return ResponseEntity.ok().body(json.toString());
            }

            else if(userType == UserType.TEACHER){
                String username = jwt.getClaim("username").asString();
                Teacher teacher = teacherService.searchByTno(username);
                teacher.setPassword(modify.getPassword());
                teacherService.save(teacher);

                json.setMessage("Successfully modified password");
                json.setStatus(200);
                json.addData("status", 0);
                json.addData("token", JWTUtil.updateToken(token));
                return ResponseEntity.ok().body(json.toString());
            }
            else return null;
        }
        catch (UserTypeException e){
            json.setStatus(401);
            json.addData("status", -1);
            json.addData("message", e.getMessage());
            return ResponseEntity.ok().body(json.toString());
        }
        catch(TokenExpiredException e){
            json.setStatus(402);
            json.addData("status", -2);
            json.addData("message", e.getMessage());
            return ResponseEntity.ok().body(json.toString());
        }
        catch(Exception e){
            System.exit(1);
        }

        return null;
    }
}
